<template>
    <div class="main-container" @click.self="clickContainer" @contextmenu="contextmenu" @mousedown="mousedown">
        <button @click="combineComponent">组合组件</button>
        <button @click="unCombineComponent">取消组合</button>
        <div class="main-workspace" ref="mainWorkspace" @click.self="clickWorkSapce">
            <DragResize 
                v-for="(item, index) in componentList" 
                :key="index"
                :style="item.style"
                :active="item.active"
                :index="index"
                :componetInfo="item"
                @activate="activateByIndex"
                @dargNodeMoveing="dargNodeMoveing"
                @resizeNode="resizeNode"
                >
                <component v-if="item.component_type !== 'group'"
                    :is="item.component_type"
                    style="height: 100%; width: 100%">
                    </component>
                <div v-else style="height: 100%; width: 100%">
                    <component v-for="(child, index) in item.childList" :key="index"
                        :is="child.component_type"
                        :style="child.style"></component>
                </div>
            </DragResize>
            <multiterm-active-container
                @click.native="initComponentsActiveateStatus"
                :active="multitermActiveContainer.active"
                :style="multitermActiveContainer.style">
                </multiterm-active-container>
        </div>
    </div>
</template>

<script lang="ts">
import { Component, Model, Prop, Vue, Watch } from 'vue-property-decorator'
import DragResize from './DragResize.vue'
import MultitermActiveContainer from './MultitermActiveContainer.vue'
import { parseNumber } from '@/utils/tools'
import { uniq, min, max, cloneDeep, concat } from 'lodash'

@Component({
    components: { DragResize, MultitermActiveContainer }
})
export default class MainContainer extends Vue {
    componentList: Array<StoreState.componetInfo> = []
    headerToolsHeight: number = this.$store.state.headerToolsHeight
    activeIndexArray: number[] = []
    shiftPressStatus: boolean = false
    multitermActiveContainer = {
        active: false,
        component_type: 'group',
        style: {
            left: '0px',
            top: '0px',
            width: '0px',
            height: '0px'
        }
    }
    created() {
        document.addEventListener('keydown', event => {
            if (event.keyCode === 16) {
                this.shiftPressStatus = true
            }
        })
        document.addEventListener('keyup', event => {
            if (event.keyCode === 16) {
                this.shiftPressStatus = false
            }
        })
        this.$nextTick(() => {
            const mainWorkspace: any = this.$refs.mainWorkspace
            // 获取工作区域在main-container中的占比
            this.$store.commit('SET_workspaceArea', {
                x1y1: {x: mainWorkspace.offsetLeft, y: mainWorkspace.offsetTop},
                x2y1: {x: mainWorkspace.offsetLeft + mainWorkspace.offsetWidth, y: mainWorkspace.offsetTop},
                x1y2: {x: mainWorkspace.offsetLeft, y: mainWorkspace.offsetTop + mainWorkspace.offsetHeight},
                x2y2: {x: mainWorkspace.offsetLeft + mainWorkspace.offsetWidth, y: mainWorkspace.offsetTop + mainWorkspace.offsetHeight}
            })
        })
        // 将当前页的组件列表数据添加至全局
        this.$store.commit('SET_projectPageList_byPageId', {
            pageId: this.$store.state.currentPageId,
            componentsList: []
        })
        
    }
    getComponetListByPageId(pageId: string, projectPageList: any): Array<StoreState.componetInfo> | null {
        let componentsList = null
        projectPageList.forEach((item: StoreState.projectPageList) => {
            if (pageId === item.pageId) {
                componentsList = item.componentsList
            }
        })
        return componentsList
    }
    @Watch('$store.state.nodeMoveing')
    nodeMoveing(val: boolean, oldVal:boolean) {
        // 如果当前处于组件刚被放置的状态,就动态更改一次本页面的组件列表数据
        if (!val && oldVal) {
            let componentList = this.getComponetListByPageId(this.$store.state.currentPageId, this.$store.state.projectPageList)
            if (componentList) {
                this.componentList = componentList
            }
        }
    }
    @Watch('activeIndexArray')
    multitermActive() {
        if (this.activeIndexArray.length > 1) {
            // 当多项组件被激活时出现
            let leftArray: number[] = []
            let topArray: number[] = []
            let rightArray: number[] = []
            let bottomArray: number[] = []
            this.activeIndexArray.forEach(index => {
                const COM = this.componentList[index]
                leftArray.push(parseNumber(COM.style.left))
                topArray.push(parseNumber(COM.style.top))
                rightArray.push(parseNumber(COM.style.left) + parseNumber(COM.style.width))
                bottomArray.push(parseNumber(COM.style.top) + parseNumber(COM.style.height))
            })
            this.activateMultermContainer(leftArray, topArray, rightArray, bottomArray)
        }
    }
    /**
     * 去掉默认的菜单栏点击事件
    */
    contextmenu(event: MouseEvent) {
        event.preventDefault()
    }
    /**
     * 鼠标按下事件
    */
    mousedown(event: MouseEvent) {
        // 如果鼠标点击了右键
        if (event.button === 2) {
            this.showMenu()
        }
    }
    showMenu() {
        alert('出现菜单栏')
    }
    /**
     * 激活多项选择容器组件
    */
    activateMultermContainer(leftArray: number[], topArray: number[], rightArray: number[], bottomArray: number[]) {
        this.multitermActiveContainer.active = true
        this.multitermActiveContainer.style.left = min(leftArray) + 'px'
        this.multitermActiveContainer.style.top = min(topArray) + 'px'
        this.multitermActiveContainer.style.width = max(rightArray)! - min(leftArray)! + 'px'
        this.multitermActiveContainer.style.height = max(bottomArray)! - min(topArray)! + 'px'
    }
    /**
     * 初始化多项选择组件
     */
    initMultermContainer() {
        this.multitermActiveContainer.active = false
        this.multitermActiveContainer.style.left = '0px'
        this.multitermActiveContainer.style.top = '0px'
        this.multitermActiveContainer.style.width ='0px'
        this.multitermActiveContainer.style.height = '0px'
    }
    /**
     * 根据索引值激活组件
     * @param {number} 索引值
     */
    activateByIndex(index: number) {
        if (!this.shiftPressStatus && this.activeIndexArray.length < 2) {
            this.initComponentsActiveateStatus()
        }
        this.componentList[index].active = true
        this.activeIndexArray.push(index)
        this.setActiveIndexArray(uniq(this.activeIndexArray))
    }
    /**
     * 初始化当前页面所有组件的激活状态
     */
    initComponentsActiveateStatus() {
        this.componentList.forEach(item => {
            item.active = false
        })
        this.setActiveIndexArray([])
        this.initMultermContainer()
    }
    /**
     * 设置激活组件索引列表
    */
    setActiveIndexArray(array: number[]) {
        this.activeIndexArray = array
    }
    /**
     * 点击除组件外的整个容器区域触发的事件
    */
    clickContainer() {
        this.initComponentsActiveateStatus()
    }
    /**
     * 点击工作区域
    */
    clickWorkSapce() {
        this.initComponentsActiveateStatus()
    }
    /**
     * 目标节点处于移动中
    */
    dargNodeMoveing(move: {moveX: number, moveY: number}) {
        this.activeIndexArray.forEach(index => {
            let left = parseNumber(this.componentList[index].style.left),
                top = parseNumber(this.componentList[index].style.top)
                this.componentList[index].style.left = left + move.moveX + 'px'
                this.componentList[index].style.top = top + move.moveY + 'px'
        })
        if (this.multitermActiveContainer.active) {
            let left = parseNumber(this.multitermActiveContainer.style.left),
                top = parseNumber(this.multitermActiveContainer.style.top)
                this.multitermActiveContainer.style.left = left + move.moveX + 'px'
                this.multitermActiveContainer.style.top = top + move.moveY + 'px'
        }
    }
    /**
     * 变换节点
    */
    resizeNode(info: {index: number, left: string, top: string, width: string, height: string}) {
        this.componentList[info.index].style.left = info.left
        this.componentList[info.index].style.top = info.top
        this.componentList[info.index].style.width = info.width
        this.componentList[info.index].style.height = info.height
    }
    /**
     * 将激活的组件组合为一个组件
    */
    combineComponent() {
        if (this.activeIndexArray.length > 1) {
            // 在组合组件时先将激活组件中已有的激活组件全部打散，以此来保证可以任意组合任意组件
            this.unCombineComponent()
            let combineComponent: any = cloneDeep(this.multitermActiveContainer)
                combineComponent.childList = []
            // 将现有激活的组件进行组合操作
            this.activeIndexArray.forEach(index => {
                let componetInfo: StoreState.componetInfo = this.componentList[index]
                // 重新计算组件位置
                componetInfo.style.left = parseNumber(componetInfo.style.left) - parseNumber(this.multitermActiveContainer.style.left) + 'px'
                componetInfo.style.top = parseNumber(componetInfo.style.top) - parseNumber(this.multitermActiveContainer.style.top) + 'px'
                combineComponent.childList.push(componetInfo)
            })
            // 删除已经组合的组件
            for (let i = this.componentList.length - 1; i >= 0; i--) {
                for (let k = 0; k < this.activeIndexArray.length; k++) {
                    if (i === this.activeIndexArray[k]) {
                        this.componentList.splice(i, 1)
                    }
                }
            }
            this.componentList.push(combineComponent)
            this.setActiveIndexArray([this.componentList.length - 1])
        }
    }
    /**
     * 将激活的组合组件打散
    */
   unCombineComponent() {
        let tempCompontList: StoreState.componetInfo[] = cloneDeep(this.componentList),
            tempArray: StoreState.componetInfo[] = [],
            activateArray: number[] = []
        // 根据激活的组合组件列表获取被打散的组件列表
        this.activeIndexArray.forEach(index => {
            if (tempCompontList[index].component_type === 'group') {
                // 重新计算组件位置
                let childListInfo: StoreState.componetInfo[] = tempCompontList[index].childList.map((item: StoreState.componetInfo) => {
                    item.style.left = parseNumber(item.style.left) + parseNumber(tempCompontList[index].style.left) + 'px'
                    item.style.top = parseNumber(item.style.top) + parseNumber(tempCompontList[index].style.top) + 'px'
                    return item
                })
                tempArray = concat(tempArray, childListInfo)
                // 删除已经被打散的组合组件
                for (let i = 0; i < this.componentList.length; i++) {
                    if (i === index) {
                        this.componentList.splice(i, 1)
                        i--
                    }
                }
            } else {
                activateArray.push(index)
            }
        })
        // 设置激活的组件索引列表
        tempArray.forEach((item, index) => {
            activateArray.push(index + this.componentList.length)
        })
        this.setActiveIndexArray(activateArray)
        // 将打散的组件从新加入组件列表中
        this.componentList = concat(this.componentList, tempArray)
        // 由于此处采用深拷贝的方式导致原型链断裂，所以要重新设置全局数据中本页面的组件列表数据,
        // 这样才能够保证全局的数据与本页面的数据是相同的
        this.$store.commit('SET_projectPageList_byPageId', {
            pageId: this.$store.state.currentPageId,
            componentsList: this.componentList
        })
   }
}
</script>

<style lang="less">
.main-container {
    height: calc(~"100vh - 56px");
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    .main-workspace {
        position: relative;
        background-color: #fff;
        width: 375px;
        height: 667px;
    }
}
</style>
